/*
 * Wazuh Vulnerability Scanner - Unit Tests
 * Copyright (C) 2015, Wazuh Inc.
 * February 21, 2024.
 *
 * This program is free software; you can redistribute it
 * and/or modify it under the terms of the GNU General Public
 * License (version 2) as published by the FSF - Free Software
 * Foundation.
 */

#include "queryAllPackages_test.hpp"
#include "TrampolineOsDataCache.hpp"
#include "queryAllPackages.hpp"
#include "shared_modules/utils/mocks/chainOfResponsabilityMock.h"

const std::string EXPECTED_QUERY {"agent 001 package get "};
const std::string EXPECTED_QUERY_MANAGER {"agent 0 package get "};
const std::string PACKAGES_RESPONSE {
    R"(ok [{"architecture":"x86_64","checksum":"qwerty","description":"Web Browser","format":"deb","groups":"","install_time":"02/22/2024 00:00:00","item_id":"ytrewq","location":"","multiarch":"","name":"Firefox","priority":"","scan_time":"02/21/2024 00:00:00","size":0,"source":"","vendor":"canonical","version":"122.0.1"},{"architecture":"x86_64","checksum":"asdfgh","description":"Text editor","format":"deb","groups":"","install_time":"02/22/2024 00:00:00","item_id":"hgfdsa","location":"","multiarch":"","name":"Neovim","priority":"","scan_time":"02/21/2024 00:00:00","size":0,"source":"","vendor":"canonical","version":"0.9.5"}])"};

TEST_F(QueryAllPackagesTest, SingleDeleteAndInsertTest)
{
    m_socketServer->listen(
        [&](const int fd, const char* data, uint32_t size, const char* dataHeader, uint32_t sizeHeader)
        {
            std::ignore = dataHeader;
            std::ignore = sizeHeader;

            std::string receivedMsg(data, size);
            EXPECT_STREQ(receivedMsg.c_str(), EXPECTED_QUERY.c_str());

            m_socketServer->send(fd, PACKAGES_RESPONSE.c_str(), PACKAGES_RESPONSE.size());
        });

    Os osData {.hostName = "osdata_hostname",
               .architecture = "osdata_architecture",
               .name = "osdata_name",
               .codeName = "upstream",
               .majorVersion = "osdata_majorVersion",
               .minorVersion = "osdata_minorVersion",
               .patch = "osdata_patch",
               .build = "osdata_build",
               .platform = "osdata_platform",
               .version = "osdata_version",
               .release = "osdata_release",
               .displayVersion = "osdata_displayVersion",
               .sysName = "osdata_sysName",
               .kernelVersion = "osdata_kernelVersion",
               .kernelRelease = "osdata_kernelRelease"};

    spOsDataCacheMock = std::make_shared<MockOsDataCache>();
    EXPECT_CALL(*spOsDataCacheMock, getOsData(testing::_)).WillRepeatedly(testing::Return(osData));

    auto spPackageInsertOrchestrationMock =
        std::make_shared<MockAbstractHandler<std::shared_ptr<TScanContext<TrampolineOsDataCache>>>>();
    // Called twice because the server socket response has two packages.
    EXPECT_CALL(*spPackageInsertOrchestrationMock, handleRequest(testing::_)).Times(2);

    auto queryAllPackages =
        std::make_shared<TQueryAllPackages<TScanContext<TrampolineOsDataCache>,
                                           MockAbstractHandler<std::shared_ptr<TScanContext<TrampolineOsDataCache>>>>>(
            spPackageInsertOrchestrationMock);

    nlohmann::json jsonData = nlohmann::json::parse(
        R"({"agent_info":  {"agent_id":"001",  "agent_version":"4.8.0",  "agent_name":"test_agent_name",  "agent_ip":"10.0.0.1",  "node_name":"node01"},  "action":"upgradeAgentDB"})");

    std::variant<const SyscollectorDeltas::Delta*, const SyscollectorSynchronization::SyncMsg*, const nlohmann::json*>
        data = &jsonData;

    auto contextData = std::make_shared<TScanContext<TrampolineOsDataCache>>(data);

    queryAllPackages->handleRequest(contextData);
}

TEST_F(QueryAllPackagesTest, InsertAllTest)
{
    m_socketServer->listen(
        [&](const int fd, const char* data, uint32_t size, const char* dataHeader, uint32_t sizeHeader)
        {
            std::ignore = dataHeader;
            std::ignore = sizeHeader;

            std::string receivedMsg(data, size);
            EXPECT_STREQ(receivedMsg.c_str(), EXPECTED_QUERY_MANAGER.c_str());

            m_socketServer->send(fd, PACKAGES_RESPONSE.c_str(), PACKAGES_RESPONSE.size());
        });

    Os osData {.hostName = "osdata_hostname",
               .architecture = "osdata_architecture",
               .name = "osdata_name",
               .codeName = "upstream",
               .majorVersion = "osdata_majorVersion",
               .minorVersion = "osdata_minorVersion",
               .patch = "osdata_patch",
               .build = "osdata_build",
               .platform = "osdata_platform",
               .version = "osdata_version",
               .release = "osdata_release",
               .displayVersion = "osdata_displayVersion",
               .sysName = "osdata_sysName",
               .kernelVersion = "osdata_kernelVersion",
               .kernelRelease = "osdata_kernelRelease"};

    spOsDataCacheMock = std::make_shared<MockOsDataCache>();
    EXPECT_CALL(*spOsDataCacheMock, getOsData(testing::_)).WillRepeatedly(testing::Return(osData));

    auto spPackageInsertOrchestrationMock =
        std::make_shared<MockAbstractHandler<std::shared_ptr<TScanContext<TrampolineOsDataCache>>>>();
    // Called twice because the server socket response has two packages.
    EXPECT_CALL(*spPackageInsertOrchestrationMock, handleRequest(testing::_)).Times(2);

    auto queryAllPackages =
        std::make_shared<TQueryAllPackages<TScanContext<TrampolineOsDataCache>,
                                           MockAbstractHandler<std::shared_ptr<TScanContext<TrampolineOsDataCache>>>>>(
            spPackageInsertOrchestrationMock);

    nlohmann::json jsonData = nlohmann::json::parse(
        R"([{"connection_status":"active","date_add":1708711832,"disconnection_time":0,"group_config_status":"synced","group_sync_status":"synced","id":0,"ip":"127.0.0.1","last_keepalive":253402300799,"manager_host":"jammy","name":"jammy","node_name":"node01","os_arch":"x86_64","os_codename":"Jammy Jellyfish","os_major":"22","os_minor":"04","os_name":"Ubuntu","os_platform":"ubuntu","os_uname":"Linux |jammy |5.15.0-94-generic |#104-Ubuntu SMP Tue Jan 9 15:25:40 UTC 2024 |x86_64","os_version":"22.04.1 LTS","register_ip":"127.0.0.1","status_code":0,"sync_status":"synced","version":"Wazuh v4.8.0"}])");

    std::variant<const SyscollectorDeltas::Delta*, const SyscollectorSynchronization::SyncMsg*, const nlohmann::json*>
        data = &jsonData;

    auto contextData = std::make_shared<TScanContext<TrampolineOsDataCache>>(data);

    queryAllPackages->handleRequest(contextData);
}

TEST_F(QueryAllPackagesTest, DISABLED_InsertAllTestNotSyncedResponse)
{
    m_socketServer->listen(
        [&](const int fd, const char* data, uint32_t size, const char* dataHeader, uint32_t sizeHeader)
        {
            std::ignore = dataHeader;
            std::ignore = sizeHeader;

            std::string receivedMsg(data, size);
            EXPECT_STREQ(receivedMsg.c_str(), EXPECTED_QUERY_MANAGER.c_str());

            m_socketServer->send(fd, PACKAGES_RESPONSE.c_str(), PACKAGES_RESPONSE.size());
        });

    Os osData {.hostName = "osdata_hostname",
               .architecture = "osdata_architecture",
               .name = "osdata_name",
               .codeName = "upstream",
               .majorVersion = "osdata_majorVersion",
               .minorVersion = "osdata_minorVersion",
               .patch = "osdata_patch",
               .build = "osdata_build",
               .platform = "osdata_platform",
               .version = "osdata_version",
               .release = "osdata_release",
               .displayVersion = "osdata_displayVersion",
               .sysName = "osdata_sysName",
               .kernelVersion = "osdata_kernelVersion",
               .kernelRelease = "osdata_kernelRelease"};

    spOsDataCacheMock = std::make_shared<MockOsDataCache>();
    EXPECT_CALL(*spOsDataCacheMock, getOsData(testing::_)).WillRepeatedly(testing::Return(osData));

    auto spPackageInsertOrchestrationMock =
        std::make_shared<MockAbstractHandler<std::shared_ptr<TScanContext<TrampolineOsDataCache>>>>();
    // Called twice because the server socket response has two packages.
    EXPECT_CALL(*spPackageInsertOrchestrationMock, handleRequest(testing::_)).Times(0);

    auto queryAllPackages =
        std::make_shared<TQueryAllPackages<TScanContext<TrampolineOsDataCache>,
                                           MockAbstractHandler<std::shared_ptr<TScanContext<TrampolineOsDataCache>>>>>(
            spPackageInsertOrchestrationMock);

    nlohmann::json jsonData = nlohmann::json::parse(R"([{"status":"NOT_SYNCED"}])");

    std::variant<const SyscollectorDeltas::Delta*, const SyscollectorSynchronization::SyncMsg*, const nlohmann::json*>
        data = &jsonData;

    auto contextData = std::make_shared<TScanContext<TrampolineOsDataCache>>(data);

    queryAllPackages->handleRequest(contextData);
}
